package com.zzyl.nursing.service.impl;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.core.redis.RedisCache;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.nursing.domain.dto.DeviceDto;
import com.zzyl.nursing.domain.po.Device;
import com.zzyl.nursing.domain.vo.DeviceDetailVo;
import com.zzyl.nursing.domain.vo.DevicePropertiesVo;
import com.zzyl.nursing.domain.vo.ProductVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.DeviceMapper;

import com.zzyl.nursing.service.IDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * 设备Service业务层处理
 *
 * @author alexis
 * @date 2025-06-05
 */
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService {
    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private IoTDAClient ioTDAClient;

    /**
     * 查询设备
     *
     * @param id 设备主键
     * @return 设备
     */
    @Override
    public Device selectDeviceById(Long id) {
        return deviceMapper.selectById(id);
    }

    /**
     * 查询设备列表
     *
     * @param device 设备
     * @return 设备
     */
    @Override
    public List<Device> selectDeviceList(Device device) {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增设备
     *
     * @param device 设备
     * @return 结果
     */
    @Override
    public int insertDevice(Device device) {
        return deviceMapper.insert(device);
    }

    /**
     * 修改设备
     *
     * @param device 设备
     * @return 结果
     */
    @Override
    public int updateDevice(Device device) {
        return deviceMapper.updateById(device);
    }

    /**
     * 批量删除设备
     *
     * @param ids 需要删除的设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(Long[] ids) {
        return deviceMapper.deleteBatchIds(Arrays.asList(ids));
    }

    @Override
    public List<ProductVO> allProduct() {
        List<Map<String, Object>> mapList = (List<Map<String, Object>>) redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_KEY);
        List<ProductVO> productVOS = new ArrayList<>();
        mapList.forEach(e -> {

            String productId = (String) e.get("product_id");
            String name = (String) e.get("name");
            ProductVO productVO = new ProductVO(productId, name);
            productVOS.add(productVO);

        });


        if (CollectionUtil.isEmpty(productVOS)) {
            return List.of();
        }
        return productVOS;
    }

    @Override
    public void syncProductList() {
        ListProductsRequest listProductsRequest = new ListProductsRequest();
        listProductsRequest.setLimit(50);
        ListProductsResponse response = ioTDAClient.listProducts(listProductsRequest);

        if (response.getHttpStatusCode() != 200) {
            throw new BaseException("查询失败");
        }
        List<ProductSummary> products = response.getProducts();


        redisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCT_KEY, products);
    }

    /**
     * 删除设备信息
     *
     * @param id 设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceById(Long id) {
        return deviceMapper.deleteById(id);
    }

    @Override
    public void register(DeviceDto deviceDto) {
        Long count = lambdaQuery().eq(Device::getDeviceName, deviceDto.getDeviceName()).count();
        if (count > 0) {
            throw new BaseException("设备重复");
        }
        count = lambdaQuery().eq(Device::getIotId, deviceDto.getIotId()).count();
        if (count > 0) {
            throw new BaseException("设备标识重复");
        }
        if (deviceDto.getLocationType() == 0) {
            deviceDto.setPhysicalLocationType(-1);
        }
        count = lambdaQuery().eq(Device::getBindingLocation, deviceDto.getBindingLocation())
                .eq(Device::getProductKey, deviceDto.getProductKey())
                .eq(Device::getPhysicalLocationType, deviceDto.getPhysicalLocationType())
                .eq(Device::getLocationType, deviceDto.getLocationType()).count();
        if (count > 0) {
            throw new BaseException("绑定重复产品");
        }

        //注册设备，iot


        AddDeviceRequest addDeviceRequest = new AddDeviceRequest();
        AddDevice addDevice = new AddDevice();
        addDevice.withNodeId(deviceDto.getNodeId()).
                withDeviceName(deviceDto.getDeviceName()).
                withProductId(deviceDto.getProductKey());


        addDeviceRequest.withBody(addDevice);

        AddDeviceResponse response = ioTDAClient.addDevice(addDeviceRequest);

        Device device = BeanUtil.toBean(deviceDto, Device.class);

        String iotId = response.getDeviceId();
        String secret = response.getAuthInfo().getSecret();
        device.setSecret(secret);
        device.setIotId(iotId);

        save(device);

    }

    @Override
    public DeviceDetailVo getById(String iotId) {
        Device device = lambdaQuery().eq(Device::getIotId, iotId).one();
        if (ObjectUtil.isEmpty(device)) {
            throw new BaseException("没有");
        }

        DeviceDetailVo detailVo = BeanUtil.toBean(device, DeviceDetailVo.class);
        ShowDeviceRequest showDeviceRequest = new ShowDeviceRequest();
        showDeviceRequest.withDeviceId(iotId.toString());

        ShowDeviceResponse response = ioTDAClient.showDevice(showDeviceRequest);

//        获取状态
        String status = response.getStatus();

        String activeTime = response.getActiveTime();
        if (StringUtils.isNotEmpty(activeTime)) {
            LocalDateTime time = LocalDateTimeUtil.parse(activeTime, DatePattern.UTC_MS_PATTERN);
            //日期时区转换
            time = time.atZone(ZoneId.from(ZoneOffset.UTC))
                    .withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                    .toLocalDateTime();
            detailVo.setActiveTime(time);
        }

        detailVo.setDeviceStatus(status);


        return detailVo;
    }

    @Override
    public void edit(DeviceDto deviceDto) {

//      判断设备名不能重复。

        Long counted = lambdaQuery().eq(Device::getDeviceName, deviceDto.getDeviceName())
                .ne(Device::getId, deviceDto.getId()).count();
        if (counted > 0) {
            throw new BaseException("设备名重复");
        }

//      老人传入的 locationtype 是0 PhysicalLocationType是null,所以我们要把它修改为-1，让他正确。
        if (deviceDto.getLocationType() == 0) {
            deviceDto.setPhysicalLocationType(-1);
        }

//       排除自己，查询要插入的老人是否有同类型的设备
        Long count = lambdaQuery().ne(Device::getId, deviceDto.getId())
                .eq(Device::getPhysicalLocationType, deviceDto.getPhysicalLocationType())
                .eq(Device::getLocationType, deviceDto.getLocationType())
                .eq(Device::getBindingLocation, deviceDto.getBindingLocation())
                .eq(Device::getProductKey, deviceDto.getProductKey())
                .count();
        if (count > 0) {
            throw new BaseException("重复设备出现在老人身上");
        }

        Device dev = BeanUtil.toBean(deviceDto, Device.class);

        updateDevice(dev);


        Device device = lambdaQuery().eq(Device::getId, deviceDto.getId()).one();

        UpdateDeviceRequest request = new UpdateDeviceRequest();
        request.withDeviceId(device.getIotId());
        UpdateDevice updateDevice = new UpdateDevice();
        updateDevice.withDeviceName(deviceDto.getDeviceName());

        request.withBody(updateDevice);


        ioTDAClient.updateDevice(request);


    }

    @Override
    public void delete(String iotId) {
        try {
            int delete = baseMapper.delete(new LambdaQueryWrapper<Device>().eq(Device::getIotId, iotId));
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setDeviceId(iotId);
            DeleteDeviceResponse deleteDeviceResponse = ioTDAClient.deleteDevice(deleteDeviceRequest);
        } catch (Exception e) {
            throw new RuntimeException("删除失败");
        }

    }

    @Override
    public List<DevicePropertiesVo> queryServiceProperties(String iotId) {
        ShowDeviceShadowRequest request = new ShowDeviceShadowRequest();
        request.withDeviceId(iotId);

        ShowDeviceShadowResponse response = ioTDAClient.showDeviceShadow(request);

        List<DeviceShadowData> shadow = response.getShadow();

        List<DevicePropertiesVo> devicePropertiesVos=new ArrayList<>();

        shadow.forEach(s->{
            LinkedHashMap<String, Object> properties = (LinkedHashMap<String, Object>) s.getReported().getProperties();

            properties.keySet().forEach(e->{
                DevicePropertiesVo devicePropertiesVo = new DevicePropertiesVo();
                devicePropertiesVo.setFunctionId(e);
                devicePropertiesVo.setValue(properties.get(e).toString());
                LocalDateTime activeTime =  LocalDateTimeUtil.parse(shadow.get(0).getReported().getEventTime(), "yyyyMMdd'T'HHmmss'Z'");
                //日期时区转换
                LocalDateTime eventTime = activeTime.atZone(ZoneId.from(ZoneOffset.UTC))
                        .withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                        .toLocalDateTime();
                devicePropertiesVo.setEventTime(eventTime);
                devicePropertiesVos.add(devicePropertiesVo);
            });

        });

        return devicePropertiesVos;

    }
}
